home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / GZIP107S.ZIP;1 / GZIP107.TAR / gzip-1.0.7 / gzip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-18  |  39.7 KB  |  1,370 lines

  1. /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
  2.  * Copyright (C) 1992-1993 Jean-loup Gailly
  3.  * The unzip code was written and put in the public domain by Mark Adler.
  4.  * Portions of the lzw code are derived from the public domain 'compress'
  5.  * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
  6.  * Ken Turkowski, Dave Mack and Peter Jannesen.
  7.  *
  8.  * See the license_msg below and the file COPYING for the software license.
  9.  * See the file algorithm.doc for the compression algorithms and file formats.
  10.  */
  11.  
  12. static char  *license_msg[] = {
  13. "   Copyright (C) 1992-1993 Jean-loup Gailly",
  14. "   This program is free software; you can redistribute it and/or modify",
  15. "   it under the terms of the GNU General Public License as published by",
  16. "   the Free Software Foundation; either version 2, or (at your option)",
  17. "   any later version.",
  18. "",
  19. "   This program is distributed in the hope that it will be useful,",
  20. "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
  21. "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
  22. "   GNU General Public License for more details.",
  23. "",
  24. "   You should have received a copy of the GNU General Public License",
  25. "   along with this program; if not, write to the Free Software",
  26. "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
  27. 0};
  28.  
  29. /* Compress files with zip algorithm and 'compress' interface.
  30.  * See usage() and help() functions below for all options.
  31.  * Outputs:
  32.  *        file.z:   compressed file with same mode, owner, and utimes
  33.  *        file.Z:   same with -Z option (old compress format)
  34.  *     or stdout with -c option or if stdin used as input.
  35.  * If the OS does not support file names with multiple dots (MSDOS, VMS) or
  36.  * if the output file name had to be truncated, the original name is kept
  37.  * in the compressed .z file. (Feature not available in old compress format.)
  38.  * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-z.
  39.  *
  40.  * For the meaning of all compilation flags, see comments in Makefile.in.
  41.  */
  42.  
  43. #ifndef lint
  44. static char rcsid[] = "$Id: gzip.c,v 0.17 1993/03/18 18:14:56 jloup Exp $";
  45. #endif
  46.  
  47. #include "tailor.h"
  48. #include "gzip.h"
  49. #include "lzw.h"
  50. #include "revision.h"
  51. #include "getopt.h"
  52.  
  53. #include <stdio.h>
  54. #include <ctype.h>
  55. #include <sys/types.h>
  56. #include <signal.h>
  57. #include <sys/stat.h>
  58. #include <errno.h>
  59.  
  60.         /* configuration */
  61.  
  62. #ifndef NO_FCNTL_H
  63. #  include <fcntl.h>
  64. #endif
  65.  
  66. #ifdef HAVE_UNISTD_H
  67. #  include <unistd.h>
  68. #endif
  69.  
  70. #if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
  71. #  include <stdlib.h>
  72. #else
  73.    extern int errno;
  74. #endif
  75.  
  76. #if defined(DIRENT) || defined(_POSIX_VERSION)
  77. #  include <dirent.h>
  78.    typedef struct dirent dir_type;
  79. #  define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
  80. #  define DIR_OPT "DIRENT"
  81. #else
  82. #  define NLENGTH(dirent) ((dirent)->d_namlen)
  83. #  ifdef SYSDIR
  84. #    include <sys/dir.h>
  85.      typedef struct direct dir_type;
  86. #    define DIR_OPT "SYSDIR"
  87. #  else
  88. #    ifdef SYSNDIR
  89. #      include <sys/ndir.h>
  90.        typedef struct direct dir_type;
  91. #      define DIR_OPT "SYSNDIR"
  92. #    else
  93. #      ifdef NDIR
  94. #        include <ndir.h>
  95.          typedef struct direct dir_type;
  96. #        define DIR_OPT "NDIR"
  97. #      else
  98. #        define NO_DIR
  99. #        define DIR_OPT "NO_DIR"
  100. #      endif
  101. #    endif
  102. #  endif
  103. #endif
  104.  
  105. #ifndef NO_UTIME
  106. #  ifndef NO_UTIME_H
  107. #    include <utime.h>
  108. #    define TIME_OPT "UTIME"
  109. #  else
  110. #    ifdef HAVE_SYS_UTIME_H
  111. #      include <sys/utime.h>
  112. #      define TIME_OPT "SYS_UTIME"
  113. #    else
  114.        struct utimbuf {
  115.          time_t actime;
  116.          time_t modtime;
  117.        };
  118. #      define TIME_OPT ""
  119. #    endif
  120. #  endif
  121. #else
  122. #  define TIME_OPT "NO_UTIME"
  123. #endif
  124.  
  125. #if !defined(S_ISDIR) && defined(S_IFDIR)
  126. #  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  127. #endif
  128. #if !defined(S_ISREG) && defined(S_IFREG)
  129. #  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  130. #endif
  131.  
  132. typedef RETSIGTYPE (*sig_type)();
  133.  
  134. #ifndef    O_BINARY
  135. #  define  O_BINARY  0  /* creation mode for open() */
  136. #endif
  137.  
  138. #ifndef O_CREAT
  139.    /* Pure BSD system? */
  140. #  include <sys/file.h>
  141. #  ifndef O_CREAT
  142. #    define O_CREAT FCREAT
  143. #  endif
  144. #  ifndef O_EXCL
  145. #    define O_EXCL FEXCL
  146. #  endif
  147. #endif
  148.  
  149. #define RW_USER 0600    /* creation mode for open() */
  150.  
  151. #ifndef MAX_PATH_LEN
  152. #  define MAX_PATH_LEN   1024 /* max pathname length */
  153. #endif
  154.  
  155. #define MAX_HEADER_LEN   16
  156. /* max length of a compressed file header, fixed part only */
  157.  
  158.         /* global buffers */
  159.  
  160. DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  161. DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  162. DECLARE(ush, d_buf,  DIST_BUFSIZE);
  163. DECLARE(uch, window, 2L*WSIZE);
  164. #ifndef MAXSEG_64K
  165.     DECLARE(ush, tab_prefix, 1L<<BITS);
  166. #else
  167.     DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
  168.     DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
  169. #endif
  170.  
  171.         /* local variables */
  172.  
  173. int to_stdout = 0;    /* output to stdout (-c) */
  174. int decompress = 0;   /* decompress (-d) */
  175. int force = 0;        /* don't ask questions, compress links (-f) */
  176. int recursive = 0;    /* recurse through directories (-r) */
  177. int verbose = 0;      /* be verbose (-v) */
  178. int quiet = 0;        /* be very quiet (-q) */
  179. int quit_on_tty = 0;  /* quit if compressing to or decompressing from a tty */
  180. int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
  181. int test = 0;         /* test .z file integrity */
  182. int foreground;       /* set if program run in foreground */
  183. char *progname;       /* program name */
  184. int maxbits = BITS;   /* max bits per code for LZW */
  185. int method = DEFLATED;/* compression method */
  186. int level = 5;        /* compression level */
  187. int exit_code = OK;   /* program exit code */
  188. int save_orig_name;   /* set if original name must be saved */
  189. int last_member;      /* set for .zip and .Z files */
  190. int part_nb;          /* number of parts in .z file */
  191. ulg time_stamp;       /* original time stamp (modification time) */
  192. long ifile_size;      /* input file size, -1 for devices (debug only) */
  193. char *env;            /* contents of GZIP env variable */
  194. char **args = NULL;   /* argv pointer if GZIP env variable defined */
  195.  
  196. long bytes_in;             /* number of input bytes */
  197. long bytes_out;            /* number of output bytes */
  198. char ifname[MAX_PATH_LEN]; /* input filename */
  199. char ofname[MAX_PATH_LEN]; /* output filename */
  200. int  remove_ofname = 0;       /* remove output file on error */
  201. struct stat istat;         /* status for input file */
  202. int  ifd;                  /* input file descriptor */
  203. int  ofd;                  /* output file descriptor */
  204. unsigned insize;           /* valid bytes in inbuf */
  205. unsigned inptr;            /* index of next byte to be processed in inbuf */
  206. unsigned outcnt;           /* bytes in output buffer */
  207.  
  208. struct option longopts[] =
  209. {
  210.  /* { name  has_arg  *flag  val } */
  211.  /* {"ascii",      0, 0, 'a'},  ascii text mode */
  212.     {"stdout",     0, 0, 'c'}, /* write output on standard output */
  213.     {"decompress", 0, 0, 'd'}, /* decompress */
  214.     {"uncompress", 0, 0, 'd'}, /* decompress */
  215.  /* {"encrypt",    0, 0, 'e'},    encrypt */
  216.     {"force",      0, 0, 'f'}, /* force overwrite of output file */
  217.     {"help",       0, 0, 'h'}, /* give help */
  218.  /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
  219.  /* {"list",       0, 0, 'l'},    list .z file contents */
  220.     {"license",    0, 0, 'L'}, /* display software license */
  221.     {"quiet",      0, 0, 'q'}, /* quiet mode */
  222.     {"recurse",    0, 0, 'r'}, /* recurse through directories */
  223.     {"test",       0, 0, 't'}, /* test compressed file integrity */
  224.     {"verbose",    0, 0, 'v'}, /* verbose mode */
  225.     {"version",    0, 0, 'V'}, /* display version number */
  226.     {"fast",       0, 0, '1'}, /* compress faster */
  227.     {"best",       0, 0, '9'}, /* compress better */
  228.     {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
  229.     {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
  230.     { 0, 0, 0, 0 }
  231. };
  232.  
  233. /* local functions */
  234.  
  235. local void usage        OF((void));
  236. local void help         OF((void));
  237. local void license      OF((void));
  238. local void version      OF((void));
  239. local void treat_stdin  OF((void));
  240. local void treat_file   OF((char *iname));
  241. local int create_outfile OF((void));
  242. local int  do_stat      OF((char *name, struct stat *sbuf));
  243. local char *get_suffix  OF((char *name));
  244. local int  get_istat    OF((char *iname, struct stat *sbuf));
  245. local int  make_ofname  OF((void));
  246. local int  same_file    OF((struct stat *stat1, struct stat *stat2));
  247. local int name_too_long OF((char *name, struct stat *statb));
  248. local int  get_method   OF((int in));
  249. local int  check_ofname OF((void));
  250. local void reset_times  OF((char *name, struct stat *statb));
  251. local void copy_stat    OF((struct stat *ifstat));
  252. local void treat_dir    OF((char *dir));
  253. local void do_exit      OF((int exitcode));
  254.       int main          OF((int argc, char **argv));
  255.  
  256. void (*work) OF((int infile, int outfile)) = zip; /* function to call */
  257.  
  258. #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
  259.  
  260. /* ======================================================================== */
  261. local void usage()
  262. {
  263.     fprintf(stderr,
  264. #ifdef LZW
  265. #  ifdef NO_DIR
  266.             "usage: %s [-cdfhLtvVZ19] [-b maxbits] [file ...]\n",
  267. #  else
  268.             "usage: %s [-cdfhLrtvVZ19] [-b maxbits] [file ...]\n",
  269. #  endif
  270. #else /* !LZW */
  271. #  ifdef NO_DIR
  272.             "usage: %s [-cdfhLtvV19] [file ...]\n",
  273. #  else
  274.             "usage: %s [-cdfhLrtvV19] [file ...]\n",
  275. #  endif
  276. #endif /* LZW */
  277.              progname);
  278. }
  279. /* ======================================================================== */
  280. local void help()
  281. {
  282.     static char  *help_msg[] = {
  283. /* -a --ascii       ascii text; convert end-of-lines to local OS conventions */
  284.  " -c --stdout      write on standard output, keep original files unchanged",
  285.  " -d --decompress  decompress",
  286. /* -e --encrypt     encrypt */
  287.  " -f --force       force overwrite of output file and compress links",
  288.  " -h --help        give this help",
  289. /* -k --pkzip       force output in pkzip format */
  290. /* -l --list        list .z file contents */
  291.  " -L --license     display software license",
  292.  " -q --quiet       suppress all warnings",
  293. #ifndef NO_DIR
  294.  " -r --recurse     recurse through directories",
  295. #endif
  296.  " -t --test        test compressed file integrity",
  297.  " -v --verbose     verbose mode",
  298.  " -V --version     display version number",
  299.  " -1 --fast        compress faster",
  300.  " -9 --best        compress better",
  301. #ifdef LZW
  302.  " -Z --lzw         produce output compatible with old compress",
  303.  " -b --bits maxbits   max number of bits per code (implies -Z)",
  304. #endif
  305.  " file...          files to (de)compress. If none given, use standard input.",
  306.   0};
  307.     char **p = help_msg;
  308.  
  309.     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
  310.     usage();
  311.     while (*p) fprintf(stderr, "%s\n", *p++);
  312. }
  313.  
  314. /* ======================================================================== */
  315. local void license()
  316. {
  317.     char **p = license_msg;
  318.  
  319.     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
  320.     while (*p) fprintf(stderr, "%s\n", *p++);
  321. }
  322.  
  323. /* ======================================================================== */
  324. local void version()
  325. {
  326.     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
  327.  
  328.     fprintf(stderr, "Compilation options:\n%s %s ", DIR_OPT, TIME_OPT);
  329. #ifdef STDC_HEADERS
  330.     fprintf(stderr, "STDC_HEADERS ");
  331. #endif
  332. #ifdef HAVE_UNISTD_H
  333.     fprintf(stderr, "HAVE_UNISTD_H ");
  334. #endif
  335. #ifdef NO_MEMORY_H
  336.     fprintf(stderr, "NO_MEMORY_H ");
  337. #endif
  338. #ifdef NO_STRING_H
  339.     fprintf(stderr, "NO_STRING_H ");
  340. #endif
  341. #ifdef NO_SYMLINK
  342.     fprintf(stderr, "NO_SYMLINK ");
  343. #endif
  344. #ifdef NO_MULTIPLE_DOTS
  345.     fprintf(stderr, "NO_MULTIPLE_DOTS ");
  346. #endif
  347. #ifdef NO_CHOWN
  348.     fprintf(stderr, "NO_CHOWN ");
  349. #endif
  350. #ifdef PROTO
  351.     fprintf(stderr, "PROTO ");
  352. #endif
  353. #ifdef ASMV
  354.     fprintf(stderr, "ASMV ");
  355. #endif
  356. #ifdef DEBUG
  357.     fprintf(stderr, "DEBUG ");
  358. #endif
  359. #ifdef DYN_ALLOC
  360.     fprintf(stderr, "DYN_ALLOC ");
  361. #endif
  362. #ifdef MAXSEG_64K
  363.     fprintf(stderr, "MAXSEG_64K");
  364. #endif
  365.     fprintf(stderr, "\n");
  366. }
  367.  
  368. /* ======================================================================== */
  369. int main (argc, argv)
  370.     int argc;
  371.     char **argv;
  372. {
  373.     int file_count = 0; /* number of files to precess */
  374.     int proglen;        /* length of progname */
  375.     int optc;           /* current option */
  376.  
  377.     EXPAND(argc, argv); /* wild card expansion if necessary */
  378.  
  379.     progname = basename(argv[0]);
  380.     proglen = strlen(progname);
  381.  
  382.     /* Suppress .exe for MSDOS, OS/2 and VMS: */
  383.     if (proglen > 4 && strequ(progname+proglen-4, ".exe")) {
  384.         progname[proglen-4] = '\0';
  385.     }
  386.  
  387.     /* Add options in GZIP environment variable if there is one */
  388.     env = add_envopt(&argc, &argv, OPTIONS_VAR);
  389.     if (env != NULL) args = argv;
  390.  
  391.     foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
  392.     if (foreground) {
  393.     signal (SIGINT, (sig_type)abort_gzip);
  394.     }
  395. #ifdef SIGTERM
  396.     signal(SIGTERM, (sig_type)abort_gzip);
  397. #endif
  398. #ifdef SIGHUP
  399.     signal(SIGHUP,  (sig_type)abort_gzip);
  400. #endif
  401.  
  402. #ifndef GNU_STANDARD
  403.     /* For compatibility with old compress, use program name as an option.
  404.      * If you compile with -DGNU_STANDARD, this program will behave as
  405.      * gzip even if it is invoked under the name gunzip or zcat.
  406.      *
  407.      * Systems which do not support links can still use -d or -dc.
  408.      * Ignore an .exe extension for MSDOS, OS/2 and VMS.
  409.      */
  410.     if (  strncmp(progname, "un",  2) == 0     /* ungzip, uncompress */
  411.        || strncmp(progname, "gun", 3) == 0) {  /* gunzip */
  412.     decompress = 1;
  413.     } else if (strequ(progname+1, "cat")       /* zcat, pcat */
  414.         || strequ(progname, "gzcat")) {    /* gzcat */
  415.     decompress = to_stdout = 1;
  416.     }
  417. #endif
  418.  
  419.     while ((optc = getopt_long (argc, argv, "b:cdfhLqrtvVZ123456789",
  420.                 longopts, (int *)0)) != EOF) {
  421.     switch (optc) {
  422.     case 'b':
  423.         maxbits = atoi(optarg);
  424.         break;
  425.     case 'c':
  426.         to_stdout = 1; break;
  427.     case 'd':
  428.         decompress = 1; break;
  429.     case 'f':
  430.         force++; break;
  431.     case 'h':
  432.         help(); do_exit(OK); break;
  433.     case 'L':
  434.         license(); do_exit(OK); break;
  435.     case 'q':
  436.         quiet = 1; verbose = 0; break;
  437.     case 'r':
  438. #ifdef NO_DIR
  439.         fprintf(stderr, "%s: -r not supported on this system\n", progname);
  440.         usage();
  441.         do_exit(ERROR); break;
  442. #else
  443.         recursive = 1; break;
  444. #endif
  445.     case 't':
  446.         test = decompress = to_stdout = 1;
  447.         break;
  448.     case 'v':
  449.         verbose++; quiet = 0; break;
  450.     case 'V':
  451.         version(); quit_on_tty = 1; break;
  452.     case 'Z':
  453. #ifdef LZW
  454.         do_lzw = 1; break;
  455. #else
  456.         fprintf(stderr, "%s: -Z not supported in this version\n",
  457.             progname);
  458.         usage();
  459.         do_exit(ERROR); break;
  460. #endif
  461.     case '1':  case '2':  case '3':  case '4':
  462.     case '5':  case '6':  case '7':  case '8':  case '9':
  463.         level = optc - '0';
  464.         break;
  465.     default:
  466.         /* Error message already emitted by getopt_long. */
  467.         usage();
  468.         do_exit(ERROR);
  469.     }
  470.     } /* loop on all arguments */
  471.  
  472.     file_count = argc - optind;
  473.  
  474.     if (do_lzw && !decompress) work = lzw;
  475.  
  476.     /* Allocate all global buffers (for DYN_ALLOC option) */
  477.     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  478.     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  479.     ALLOC(ush, d_buf,  DIST_BUFSIZE);
  480.     ALLOC(uch, window, 2L*WSIZE);
  481. #ifndef MAXSEG_64K
  482.     ALLOC(ush, tab_prefix, 1L<<BITS);
  483. #else
  484.     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
  485.     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
  486. #endif
  487.  
  488.     /* And get to work */
  489.     if (file_count != 0) {
  490.     if (to_stdout && !test) {
  491.         SET_BINARY_MODE(fileno(stdout));
  492.     }
  493.         while (optind < argc) {
  494.         treat_file(argv[optind++]);
  495.     }
  496.     } else {  /* Standard input */
  497.     treat_stdin();
  498.     }
  499.     do_exit(exit_code);
  500.     return exit_code; /* just to avoid lint warning */
  501. }
  502.  
  503. /* ========================================================================
  504.  * Compress or decompress stdin
  505.  */
  506. local void treat_stdin()
  507. {
  508.     if (isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
  509.     /* Do not send compressed data to the terminal or read it from
  510.      * the terminal. We get here when user invoked the program
  511.      * without parameters, so be helpful. However, on systems supporting
  512.          * pseudo ttys, let the beginner stare at the 'hung' program
  513.      * (explicity request from Noah Friedman). Don't give an error message
  514.      * if the user only wanted the version number (gzip -V).
  515.      */
  516.     if (quit_on_tty) do_exit(OK);
  517. #ifdef NO_PTY
  518.     fprintf(stderr,
  519.       "%s: compressed data not %s a terminal. Redirect %s file or pipe.\n",
  520.         progname, decompress ? "read from" : "written to",
  521.         decompress ? "from" : "to");
  522.     fprintf(stderr,"For help, type: %s -h\n", progname);
  523.     do_exit(ERROR);
  524. #endif
  525.     }
  526.  
  527.     SET_BINARY_MODE(fileno(stdin));
  528.     if (!test) SET_BINARY_MODE(fileno(stdout));
  529.  
  530.     strcpy(ifname, "stdin");
  531.     strcpy(ofname, "stdout");
  532.  
  533.     /* Get the time stamp on the input file */
  534. #ifdef NO_STDIN_FSTAT
  535.     time_stamp = 0; /* time unknown */
  536. #else
  537.     if (fstat(fileno(stdin), &istat) != 0) {
  538.     error("fstat(stdin)");
  539.     } 
  540.     time_stamp = istat.st_mtime;
  541. #endif
  542.     ifile_size = -1L; /* convention for unknown size */
  543.  
  544.     clear_bufs(); /* clear input and output buffers */
  545.     to_stdout = 1;
  546.     part_nb = 0;
  547.  
  548.     if (decompress) {
  549.     method = get_method(ifd);
  550.     if (method < 0) {
  551.         do_exit(exit_code); /* error message already emitted */
  552.     }
  553.     }
  554.  
  555.     /* Actually do the compression/decompression. Loop over zipped members.
  556.      */
  557.     for (;;) {
  558.     (*work)(fileno(stdin), fileno(stdout));
  559.  
  560.     if (!decompress || last_member || inptr == insize) break;
  561.     /* end of file */
  562.  
  563.     method = get_method(ifd);
  564.     if (method == -1) return; /* error message already emitted */
  565.     bytes_out = 0;            /* required for length check */
  566.     }
  567.  
  568.     if (verbose) {
  569.     if (test) {
  570.         fprintf(stderr, " OK");
  571.  
  572.     } else if (!decompress) {
  573.         fprintf(stderr, "Compression: ");
  574.         display_ratio(bytes_in-bytes_out-overhead, bytes_in);
  575.     }
  576.     fprintf(stderr, "\n");
  577.     }
  578. }
  579.  
  580. /* ========================================================================
  581.  * Compress or decompress the given file
  582.  */
  583. local void treat_file(iname)
  584.     char *iname;
  585. {
  586.     /* Check if the input file is present, set ifname and istat: */
  587.     if (get_istat(iname, &istat) != 0) return;
  588.  
  589.     /* If the input name is that of a directory, recurse or ignore: */
  590.     if (S_ISDIR(istat.st_mode)) {
  591. #ifndef NO_DIR
  592.     if (recursive) {
  593.         struct stat st;
  594.         st = istat;
  595.         treat_dir(iname);
  596.         /* Warning: ifname is now garbage */
  597.         reset_times (iname, &st);
  598.     } else
  599. #endif
  600.     WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
  601.     return;
  602.     }
  603.     if (!S_ISREG(istat.st_mode)) {
  604.     WARN((stderr,
  605.           "%s: %s is not a directory or a regular file - ignored\n",
  606.           progname, ifname));
  607.     return;
  608.     }
  609.     if (istat.st_nlink > 1 && !to_stdout && !force) {
  610.     WARN((stderr, "%s: %s has %d other link%c -- unchanged\n",
  611.           progname, ifname,
  612.           (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' '));
  613.     return;
  614.     }
  615.  
  616.     ifile_size = istat.st_size;
  617.     time_stamp = istat.st_mtime;
  618.  
  619.     /* Generate output file name */
  620.     if (to_stdout) {
  621.     strcpy(ofname, "stdout");
  622.  
  623.     } else if (make_ofname() != 0) {
  624.     return;
  625.     }
  626.  
  627.     /* Open the input file and determine compression method. The mode
  628.      * parameter is ignored but required by some systems (VMS).
  629.      */
  630.     ifd = open(ifname, O_RDONLY | O_BINARY, RW_USER);
  631.     if (ifd == -1) {
  632.     perror(ifname);
  633.     exit_code = ERROR;
  634.     return;
  635.     }
  636.     clear_bufs(); /* clear input and output buffers */
  637.     part_nb = 0;
  638.  
  639.     if (decompress) {
  640.     method = get_method(ifd); /* updates ofname if original given */
  641.     if (method < 0) {
  642.         close(ifd);
  643.         return;               /* error message already emitted */
  644.     }
  645.     }
  646.  
  647.     /* If compressing to a file, check if ofname is not ambiguous
  648.      * because the operating system truncates names. Otherwise, generate
  649.      * a new ofname and save the original name in the compressed file.
  650.      */
  651.     if (to_stdout) {
  652.     ofd = fileno(stdout);
  653.     /* keep remove_ofname as zero */
  654.     } else {
  655.     if (create_outfile() == -1) return;
  656.  
  657.     if (save_orig_name && !verbose && !quiet) {
  658.         fprintf(stderr, "%s: %s compressed to %s\n",
  659.             progname, ifname, ofname);
  660.     }
  661.     }
  662.     if (verbose) {
  663.     fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ? 
  664.         "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
  665.     }
  666.  
  667.     /* Actually do the compression/decompression. Loop over zipped members.
  668.      */
  669.     for (;;) {
  670.     (*work)(ifd, ofd);
  671.  
  672.     if (!decompress || last_member || inptr == insize) break;
  673.     /* end of file */
  674.  
  675.     method = get_method(ifd);
  676.     if (method < 0) break;    /* error message already emitted */
  677.     bytes_out = 0;            /* required for length check */
  678.     }
  679.  
  680.     close(ifd);
  681.     if (!to_stdout && close(ofd)) {
  682.     write_error();
  683.     }
  684.     if (method == -1) return;     /* error, don't display success msg */
  685.  
  686.     /* Display statistics */
  687.     if(verbose) {
  688.     if (!decompress) {
  689.         display_ratio(bytes_in-bytes_out-overhead, bytes_in);
  690.     }
  691.     if (test) {
  692.         fprintf(stderr, " OK");
  693.     } else if (!to_stdout) {
  694.         fprintf(stderr, " -- replaced with %s", ofname);
  695.     }
  696.     fprintf(stderr, "\n");
  697.     }
  698.     /* Copy modes, times, ownership */
  699.     if (!to_stdout) {
  700.     copy_stat(&istat);
  701.     }
  702. }
  703.  
  704. /* ========================================================================
  705.  * Create the output file. Return 0 for success, -1 for error.
  706.  * Try twice if ofname is exactly one beyond the name limit, to avoid
  707.  * creating a compressed file of name "1234567890123."
  708.  * We could actually loop more than once if the user gives an extra long
  709.  * name, but I prefer generating an error then. (Posix forbids the system
  710.  * to truncate names.) The error message is generated by check_ofname()
  711.  * in this case.
  712.  * IN assertions: the input file has already been open (ifd is set) and
  713.  *   ofname has already been updated if there was an original name.
  714.  * OUT assertions: ifd and ofd are closed in case of error.
  715.  */
  716. local int create_outfile()
  717. {
  718.     struct stat    ostat; /* stat for ofname */
  719.     int n;             /* loop counter */
  720.  
  721.     for (n = 1; n <= 2; n++) {
  722.     if (check_ofname() == -1) {
  723.         close(ifd);
  724.         return -1;
  725.     }
  726.     /* Create the output file */
  727.     remove_ofname = 1;
  728.     ofd = open(ofname, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, RW_USER);
  729.     if (ofd == -1) {
  730.         perror(ofname);
  731.         close(ifd);
  732.         exit_code = ERROR;
  733.         return -1;
  734.     }
  735.  
  736.     /* Check for name truncation on new file (1234567890123.z) */
  737.     if (fstat(ofd, &ostat) != 0) {
  738.         fprintf(stderr, "%s: ", progname);
  739.         perror(ofname);
  740.         close(ifd); close(ofd);
  741.         unlink(ofname);
  742.         exit_code = ERROR;
  743.         return -1;
  744.     }
  745.     if (!name_too_long(ofname, &ostat)) return 0;
  746.  
  747.     if (decompress) {
  748.         /* name might be too long if an original name was saved */
  749.         WARN((stderr, "%s: %s: warning, name truncated\n",
  750.           progname, ofname));
  751.         return 0;
  752.     } else {
  753. #ifdef NO_MULTIPLE_DOTS
  754.         /* Should never happen, see check_ofname() */
  755.         fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
  756.         do_exit(ERROR);
  757. #else
  758.         close(ofd);
  759.         unlink(ofname);
  760.         save_orig_name = 1;
  761.         strcpy(ofname+strlen(ofname)-Z_LEN-1, Z_SUFFIX);
  762.             /* 1234567890123.z -> 123456789012.z */
  763. #endif
  764.     } /* decompress ? */
  765.     } /* for (n) */
  766.  
  767.     close(ifd);
  768.     fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
  769.     exit_code = ERROR;
  770.     return -1;
  771. }
  772.  
  773. /* ========================================================================
  774.  * Use lstat if available, except for -c or -f. Use stat otherwise.
  775.  * This allows links when not removing the original file.
  776.  */
  777. local int do_stat(name, sbuf)
  778.     char *name;
  779.     struct stat *sbuf;
  780. {
  781. #if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK)
  782.     if (!to_stdout && !force) {
  783.     return lstat(name, sbuf);
  784.     }
  785. #endif
  786.     return stat(name, sbuf);
  787. }
  788.  
  789. /* ========================================================================
  790.  * Return a pointer to the 'z' suffix of a file name, or NULL.
  791.  * For all systems, ".z", ".Z", ".taz", ".tgz", "-z" are accepted suffixes.
  792.  * ".tgz" is a useful convention for tar.z files on systems limited
  793.  * to 3 characters extensions. On such systems, ".?z" and ".??z" are
  794.  * also accepted suffixes. For Unix, we do not want to accept any
  795.  * .??z suffix as indicating a compressed file; some people use .xyz
  796.  * to denote volume data.
  797.  */
  798. local char *get_suffix(name)
  799.     char *name;
  800. {
  801.     int len;
  802.     char *p = strrchr(name, '.');
  803.     char suffix[10];       /* last few chars of name, forced to lower case */
  804.  
  805.     if (p == NULL || p == name || strchr(p-1, PATH_SEP) != NULL) return NULL;
  806.     strncpy(suffix, p, sizeof(suffix));
  807.     suffix[sizeof(suffix)-1] = '\0';    /* Force null termination */
  808.  
  809. #ifdef SUFFIX_SEP
  810.     /* strip a version number from the file name */
  811.     {
  812.     char *v = strrchr(suffix, SUFFIX_SEP);
  813.     if (v != NULL) *v = '\0';
  814.     }
  815. #endif
  816.     strlwr(suffix);
  817.     if (strequ(suffix, ".z") || strequ(suffix, ".zip")
  818.     || strequ(suffix, ".tgz") || strequ(suffix, ".taz")) {
  819.     return p;
  820.     }
  821.     len = strlen(suffix);
  822.     if (len <= 2) return NULL;
  823.  
  824.     if (strequ(suffix+len-2, "-z")) return p+len-2;
  825. #ifdef MAX_EXT_CHARS
  826.     if (suffix[len-1] == 'z') return p+len-1;
  827. #endif
  828.     return NULL;
  829. }
  830.  
  831.  
  832. /* ========================================================================
  833.  * Set ifname to the input file name (with .z appended if necessary)
  834.  * and istat to its stats. Return 0 if ok, -1 if error.
  835.  */
  836. local int get_istat(iname, sbuf)
  837.     char *iname;
  838.     struct stat *sbuf;
  839. {
  840.     int iexists; /* set if iname exists */
  841.     int ilen = strlen(iname);
  842.     char *suff;
  843.  
  844.     strcpy(ifname, iname);
  845.     errno = 0;
  846.  
  847.     /* If input file exists, return OK. */
  848.     if (do_stat(ifname, sbuf) == 0) return 0;
  849.  
  850.     if (!decompress || errno != ENOENT) {
  851.     perror(ifname);
  852.     exit_code = ERROR;
  853.     return -1;
  854.     }
  855.     /* file.ext doesn't exist, try file.ext.z and file.ext.Z. For MSDOS
  856.      * try file.exz, for VMS try file.ext-z.
  857.      */
  858.     suff = get_suffix(ifname);
  859.     if (suff != NULL) {
  860.     perror(ifname); /* ifname already has z suffix and does not exist */
  861.     exit_code = ERROR;
  862.     return -1;
  863.     }
  864. #ifdef SUFFIX_SEP
  865.     /* strip a version number from the input file name */
  866.     if ((suff = strrchr(ifname, SUFFIX_SEP)) != NULL) *suff = '\0';
  867. #endif
  868.     if (strrchr(ifname, '.') != NULL) {
  869.        strcat(ifname, Z_SUFFIX);
  870.        ilen += Z_LEN;
  871.     } else {
  872.        strcat(ifname, ".z");
  873.        ilen += 2;
  874.     }
  875.     errno = 0;
  876.     iexists = !do_stat(ifname, sbuf);
  877.     if (!iexists) {
  878.     errno = 0;
  879.     ifname[ilen-1] = 'Z';
  880.     iexists = !do_stat(ifname, sbuf);
  881.     }
  882. #ifdef NO_MULTIPLE_DOTS
  883.     /* One more try just to be nice to you */
  884.     if (!iexists) {
  885.     char c = ifname[ilen-2];
  886.     errno = 0;
  887.     strcpy(ifname+ilen-2, "z");
  888.     iexists = !do_stat(ifname, sbuf);
  889.     if (!iexists) {
  890.         ifname[ilen-2] = c;
  891.     }
  892.     }
  893. #endif
  894.     if (!iexists) {
  895.     ifname[ilen-1] = 'z';
  896.     perror(ifname);
  897.     exit_code = ERROR;
  898.     return -1;
  899.     }
  900.     if (!S_ISREG (sbuf->st_mode)) {
  901.     WARN((stderr, "%s: %s: not a regular file -- ignored\n",
  902.           progname, ifname));
  903.     return -1;
  904.     }
  905.     return 0; /* ok */
  906. }
  907.  
  908. /* ========================================================================
  909.  * Generate ofname given ifname. Return 0 if ok, -1 if file must be skipped.
  910.  * Initializes save_orig_name.
  911.  * IN assertion: this function is not called if to_stdout is true.
  912.  */
  913. local int make_ofname()
  914. {
  915.     char *suff;            /* ofname z suffix */
  916.  
  917.     strcpy(ofname, ifname);
  918.     suff = get_suffix(ofname);
  919.  
  920.     if (decompress) {
  921.     if (suff == NULL) {
  922.         WARN((stderr,"%s: %s: no z suffix -- ignored\n",
  923.           progname, ifname));
  924.         return -1;
  925.     }
  926.     /* Make a special case for .tgz and .taz: */
  927.     strlwr(suff);
  928.     if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
  929.         strcpy(suff, ".tar");
  930.     } else {
  931.         *suff = '\0'; /* strip z suffix and optional version number */
  932.     }
  933.         /* ofname might be changed later if infile contains an original name */
  934.  
  935.     } else if (suff != NULL) {
  936.     /* Avoid annoying messages with -r (see treat_dir()) */
  937.     if (verbose || (!recursive && !quiet)) {
  938.         fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
  939.             progname, ifname, suff);
  940.     }
  941.     if (exit_code == OK) exit_code = WARNING;
  942.     return -1;
  943.     } else {
  944.         save_orig_name = 0;
  945.  
  946. #ifdef SUFFIX_SEP
  947.     /* strip a version number from the file name */
  948.     if ((suff = strrchr(ofname, SUFFIX_SEP)) != NULL) *suff = '\0';
  949. #endif
  950.  
  951. #ifdef NO_MULTIPLE_DOTS
  952.     suff = strrchr(ofname, '.');
  953.     if (suff != NULL) {
  954. #  ifdef MAX_EXT_CHARS
  955.         /* On the Atari and some versions of MSDOS, name_too_long()
  956.          * does not work correctly because of a bug in stat(). So we
  957.          * must truncate here.
  958.          */
  959.         if (strlen(suff) > MAX_EXT_CHARS) {
  960.         strcpy(suff + MAX_EXT_CHARS, do_lzw ? "Z" : "z");
  961.         save_orig_name = 1;
  962.         return 0;
  963.         }
  964. #  endif
  965.         strcat(ofname, Z_SUFFIX);
  966.         return 0;
  967.     }
  968. #endif
  969.     strcat(ofname, do_lzw ? ".Z" : ".z");
  970.  
  971.     } /* decompress ? */
  972.     return 0;
  973. }
  974.  
  975.  
  976. /* ========================================================================
  977.  * Check the magic number of the input file and update ofname if an
  978.  * original name was given and to_stdout is not set.
  979.  * Return the compression method, -1 for error, -2 for warning.
  980.  * Set inptr to the offset of the next byte to be processed.
  981.  * This function may be called repeatedly for an input file consisting
  982.  * of several contiguous gzip'ed members.
  983.  * IN assertions: there is at least one remaining compressed member.
  984.  *   If the member is a zip file, it must be the only one.
  985.  */
  986. local int get_method(in)
  987.     int in;        /* input file descriptor */
  988. {
  989.     uch flags;
  990.     char magic[2]; /* magic header */
  991.  
  992.     magic[0] = (char)get_byte();
  993.     magic[1] = (char)get_byte();
  994.  
  995.     time_stamp = istat.st_mtime; /* may be modified later for some methods */
  996.     method = -1;                 /* unknown yet */
  997.     part_nb++;                   /* number of parts in gzip file */
  998.     last_member = RECORD_IO;
  999.     /* assume multiple members in gzip file except for record oriented I/O */
  1000.  
  1001.     if (memcmp(magic, GZIP_MAGIC, 2) == 0
  1002.         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
  1003.  
  1004.     work = unzip;
  1005.     method = (int)get_byte();
  1006.     flags  = (uch)get_byte();
  1007.  
  1008.     if ((flags & ENCRYPTED) != 0) {
  1009.         fprintf(stderr,
  1010.             "%s: %s is encrypted -- get newer version of gzip\n",
  1011.             progname, ifname);
  1012.         exit_code = ERROR;
  1013.         return -1;
  1014.     }
  1015.     if ((flags & CONTINUATION) != 0) {
  1016.         fprintf(stderr,
  1017.        "%s: %s is a a multi-part gzip file -- get newer version of gzip\n",
  1018.             progname, ifname);
  1019.         exit_code = ERROR;
  1020.         if (force <= 1) return -1;
  1021.     }
  1022.     if ((flags & RESERVED) != 0) {
  1023.         fprintf(stderr,
  1024.             "%s: %s has flags 0x%x -- get newer version of gzip\n",
  1025.             progname, ifname, flags);
  1026.         exit_code = ERROR;
  1027.         if (force <= 1) return -1;
  1028.     }
  1029.     time_stamp  = (ulg)get_byte();
  1030.     time_stamp |= ((ulg)get_byte()) << 8;
  1031.     time_stamp |= ((ulg)get_byte()) << 16;
  1032.     time_stamp |= ((ulg)get_byte()) << 24;
  1033.  
  1034.     (void)get_byte();  /* Ignore extra flags for the moment */
  1035.     (void)get_byte();  /* Ignore OS type for the moment */
  1036.  
  1037.     if ((flags & CONTINUATION) != 0) {
  1038.         unsigned part = (unsigned)get_byte();
  1039.         part |= ((unsigned)get_byte())<<8;
  1040.         if (verbose) {
  1041.         fprintf(stderr,"%s: %s: part number %u\n",
  1042.             progname, ifname, part);
  1043.         }
  1044.     }
  1045.     if ((flags & EXTRA_FIELD) != 0) {
  1046.         unsigned len = (unsigned)get_byte();
  1047.         len |= ((unsigned)get_byte())<<8;
  1048.         if (verbose) {
  1049.         fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
  1050.             progname, ifname, len);
  1051.         }
  1052.         while (len--) (void)get_byte();
  1053.     }
  1054.  
  1055.     /* Get original file name if it was truncated */
  1056.     if ((flags & ORIG_NAME) != 0) {
  1057.         if (to_stdout || part_nb > 1) {
  1058.         /* Discard the old name */
  1059.         while (get_byte() != 0) /* null */ ;
  1060.         } else {
  1061.         /* Copy the base name. Keep a directory prefix intact. */
  1062.         char *p = basename(ofname);
  1063.         for (;;) {
  1064.             *p = (char)get_byte();
  1065.             if (*p++ == '\0') break;
  1066.             if (p >= ofname+sizeof(ofname)) {
  1067.             error("corrupted input -- file name too large");
  1068.             }
  1069.         }
  1070.         } /* to_stdout */
  1071.     } /* orig_name */
  1072.  
  1073.     /* Discard file comment if any */
  1074.     if ((flags & COMMENT) != 0) {
  1075.         while (get_byte() != 0) /* null */ ;
  1076.     }
  1077.  
  1078.     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
  1079.         && memcmp(inbuf, PKZIP_MAGIC, 4) == 0) {
  1080.     /* To simplify the code, we support a zip file when alone only.
  1081.          * We are thus guaranteed that the entire local header fits in inbuf.
  1082.          */
  1083.         inptr = 0;
  1084.     work = unzip;
  1085.     if (check_zipfile(in) == -1) return -1;
  1086.     /* check_zipfile may get ofname from the local header */
  1087.     last_member = 1;
  1088.  
  1089.     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
  1090.     work = unpack;
  1091.     method = PACKED;
  1092.     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
  1093.     work = unlzw;
  1094.     method = COMPRESSED;
  1095.     last_member = 1;
  1096.     }
  1097.     if (method >= 0) return method;
  1098.     if (part_nb == 1) {
  1099.     fprintf(stderr, "%s: %s is not in gzip format\n", progname, ifname);
  1100.     exit_code = ERROR;
  1101.     return -1;
  1102.     } else {
  1103.     WARN((stderr, "%s: %s: trailing garbage ignored\n", progname, ifname));
  1104.     return -2;
  1105.     }
  1106. }
  1107.  
  1108. /* ========================================================================
  1109.  * Return true if the two stat structures correspond to the same file.
  1110.  */
  1111. local int same_file(stat1, stat2)
  1112.     struct stat *stat1;
  1113.     struct stat *stat2;
  1114. {
  1115.     return stat1->st_mode  == stat2->st_mode
  1116.     && stat1->st_ino   == stat2->st_ino
  1117.     && stat1->st_dev   == stat2->st_dev
  1118.     && stat1->st_uid   == stat2->st_uid
  1119.     && stat1->st_gid   == stat2->st_gid
  1120.     && stat1->st_size  == stat2->st_size
  1121.     && stat1->st_atime == stat2->st_atime
  1122.     && stat1->st_mtime == stat2->st_mtime
  1123.     && stat1->st_ctime == stat2->st_ctime;
  1124. }
  1125.  
  1126. /* ========================================================================
  1127.  * Return true if a file name is ambiguous because the operating system
  1128.  * truncates file names.
  1129.  */
  1130. local int name_too_long(name, statb)
  1131.     char *name;           /* file name to check */
  1132.     struct stat *statb;   /* stat buf for this file name */
  1133. {
  1134.     int s = strlen(name);
  1135.     char c = name[s-1];
  1136.     struct stat    tstat; /* stat for truncated name */
  1137.     int res;
  1138.  
  1139.     tstat = *statb;      /* Just in case OS does not fill all fields */
  1140.     name[s-1] = '\0';
  1141.     res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
  1142.     name[s-1] = c;
  1143.     return res;
  1144. }
  1145.  
  1146. /* ========================================================================
  1147.  * If compressing to a file, check if ofname is not ambigous
  1148.  * because the operating system truncates names. Otherwise, generate
  1149.  * a new ofname and save the original name in the compressed file.
  1150.  * If the compressed file already exists, ask for confirmation.
  1151.  *    The check for name truncation is made dynamically, because different
  1152.  * file systems on the same OS might use different truncation rules (on SVR4
  1153.  * s5 truncates to 14 chars and ufs does not truncate).
  1154.  *    This function returns -1 if the file must be skipped, and
  1155.  * updates save_orig_name if necessary.
  1156.  * IN assertions: save_orig_name is already set if ofname has been
  1157.  * already truncated because of NO_MULTIPLE_DOTS. The input file has
  1158.  * already been open and istat is set.
  1159.  */
  1160. local int check_ofname()
  1161. {
  1162.     int s = strlen(ofname);
  1163.     struct stat    ostat; /* stat for ofname */
  1164.  
  1165.     if (stat(ofname, &ostat) != 0) return 0;
  1166.  
  1167.     /* Check for name truncation on existing file: */
  1168. #ifdef NO_MULTIPLE_DOTS
  1169.     if (!decompress && name_too_long(ofname, &ostat)) {
  1170. #else
  1171.     if (!decompress && s > 8 && name_too_long(ofname, &ostat)) {
  1172. #endif
  1173.     save_orig_name = 1;
  1174. #ifdef NO_MULTIPLE_DOTS
  1175.     strcpy(ofname+s-Z_LEN-1, Z_SUFFIX);  /* f.extz -> f.exz  */
  1176. #else
  1177.     strcpy(ofname+s-4, ".z"); /* 12345678901234.z -> 123456789012.z */
  1178. #endif
  1179.     if (stat(ofname, &ostat) != 0) return 0;
  1180.     } /* !decompress && name_too_long */
  1181.  
  1182.     /* Check that the input and output files are different (could be
  1183.      * the same by name truncation or links).
  1184.      */
  1185.     if (same_file(&istat, &ostat)) {
  1186.     fprintf(stderr, "%s: %s and %s are the same file\n",
  1187.         progname, ifname, ofname);
  1188.     exit_code = ERROR;
  1189.     return -1;
  1190.     }
  1191.     /* Ask permission to overwrite the existing file */
  1192.     if (!force) {
  1193.     char response[80];
  1194.     strcpy(response,"n");
  1195.     fprintf(stderr, "%s: %s already exists;", progname, ofname);
  1196.     if (foreground && isatty(fileno(stdin))) {
  1197.         fprintf(stderr, " do you wish to overwrite (y or n)? ");
  1198.         fflush(stderr);
  1199.         (void)read(fileno(stdin), response, sizeof(response));
  1200.     }
  1201.     if (tolow(*response) != 'y') {
  1202.         fprintf(stderr, "\tnot overwritten\n");
  1203.         if (exit_code == OK) exit_code = WARNING;
  1204.         return -1;
  1205.     }
  1206.     }
  1207.     (void) chmod(ofname, 0777);
  1208.     if (unlink(ofname)) {
  1209.     fprintf(stderr, "%s: ", progname);
  1210.     perror(ofname);
  1211.     exit_code = ERROR;
  1212.     return -1;
  1213.     }
  1214.     return 0;
  1215. }
  1216.  
  1217.  
  1218. /* ========================================================================
  1219.  * Set the access and modification times from the given stat buffer.
  1220.  */
  1221. local void reset_times (name, statb)
  1222.     char *name;
  1223.     struct stat *statb;
  1224. {
  1225. #ifndef NO_UTIME
  1226.     struct utimbuf    timep;
  1227.  
  1228.     /* Copy the time stamp */
  1229.     timep.actime  = statb->st_atime;
  1230.     timep.modtime = statb->st_mtime;
  1231.  
  1232.     if (utime(name, &timep)) {
  1233.     WARN((stderr, "%s: ", progname));
  1234.     if (!quiet) perror(ofname);
  1235.     }
  1236. #else
  1237.     name = name; statb = statb; /* avoid warnings */
  1238. #endif
  1239. }
  1240.  
  1241.  
  1242. /* ========================================================================
  1243.  * Copy modes, times, ownership from input file to output file.
  1244.  * IN assertion: to_stdout is false.
  1245.  */
  1246. local void copy_stat(ifstat)
  1247.     struct stat *ifstat;
  1248. {
  1249. #ifndef NO_UTIME
  1250.     time_t diff = ifstat->st_mtime - time_stamp;
  1251.  
  1252.     if (diff < 0) diff = -diff;
  1253.     if (decompress && diff > 60 && time_stamp != 0) {
  1254.     ifstat->st_mtime = time_stamp;
  1255.     if (verbose) {
  1256.         fprintf(stderr, "%s: time stamp restored\n", ofname);
  1257.     }
  1258.     }
  1259.     reset_times(ofname, ifstat);
  1260. #endif
  1261.     /* Copy the protection modes */
  1262.     if (chmod(ofname, ifstat->st_mode & 07777)) {
  1263.     WARN((stderr, "%s: ", progname));
  1264.     if (!quiet) perror(ofname);
  1265.     }
  1266. #ifndef NO_CHOWN
  1267.     chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
  1268. #endif
  1269.     remove_ofname = 0;
  1270.     /* It's now safe to remove the input file: */
  1271.     (void) chmod(ifname, 0777);
  1272.     if (unlink(ifname)) {
  1273.     WARN((stderr, "%s: ", progname));
  1274.     if (!quiet) perror(ifname);
  1275.     }
  1276. }
  1277.  
  1278. #ifndef NO_DIR
  1279.  
  1280. /* ========================================================================
  1281.  * Recurse through the given directory. This code is taken from ncompress.
  1282.  */
  1283. local void treat_dir(dir)
  1284.     char *dir;
  1285. {
  1286.     dir_type *dp;
  1287.     DIR      *dirp;
  1288.     char     nbuf[MAX_PATH_LEN];
  1289.  
  1290.     dirp = opendir(dir);
  1291.     
  1292.     if (dirp == NULL) {
  1293.     fprintf(stderr, "%s: %s unreadable\n", progname, dir);
  1294.     exit_code = ERROR;
  1295.     return ;
  1296.     }
  1297.     /*
  1298.      ** WARNING: the following algorithm could occasionally cause
  1299.      ** compress to produce error warnings of the form "<filename>.z
  1300.      ** already has .z suffix - ignored". This occurs when the
  1301.      ** .z output file is inserted into the directory below
  1302.      ** readdir's current pointer.
  1303.      ** These warnings are harmless but annoying, so they are suppressed
  1304.      ** with option -r (except when -v is on). An alternative
  1305.      ** to allowing this would be to store the entire directory
  1306.      ** list in memory, then compress the entries in the stored
  1307.      ** list. Given the depth-first recursive algorithm used here,
  1308.      ** this could use up a tremendous amount of memory. I don't
  1309.      ** think it's worth it. -- Dave Mack
  1310.      ** (An other alternative might be two passes to avoid depth-first.)
  1311.      */
  1312.     
  1313.     while ((dp = readdir(dirp)) != NULL) {
  1314.  
  1315.     if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
  1316.         continue;
  1317.     }
  1318.     if (((int)strlen(dir) + NLENGTH(dp) + 1) < (MAX_PATH_LEN - 1)) {
  1319.         strcpy(nbuf,dir);
  1320.         if (strlen(dir) != 0) { /* dir = "" means current dir on Amiga */
  1321. #ifdef OTHER_PATH_SEP
  1322.         if (dir[strlen(dir)-1] != OTHER_PATH_SEP)
  1323. #endif
  1324.         strcat(nbuf,"/");
  1325.         }
  1326.         strcat(nbuf,dp->d_name);
  1327.         treat_file(nbuf);
  1328.     } else {
  1329.         fprintf(stderr,"%s: %s/%s: pathname too long\n",
  1330.             progname, dir, dp->d_name);
  1331.         exit_code = ERROR;
  1332.     }
  1333.     }
  1334.     closedir(dirp);
  1335. }
  1336. #endif /* ? NO_DIR */
  1337.  
  1338. /* ========================================================================
  1339.  * Free all dynamically allocated variables and exit with the given code.
  1340.  */
  1341. local void do_exit(exitcode)
  1342.     int exitcode;
  1343. {
  1344.     if (env != NULL)  free(env),  env  = NULL;
  1345.     if (args != NULL) free(args), args = NULL;
  1346.     FREE(inbuf);
  1347.     FREE(outbuf);
  1348.     FREE(d_buf);
  1349.     FREE(window);
  1350. #ifndef MAXSEG_64K
  1351.     FREE(tab_prefix);
  1352. #else
  1353.     FREE(tab_prefix0);
  1354.     FREE(tab_prefix1);
  1355. #endif
  1356.     exit(exitcode);
  1357. }
  1358.  
  1359. /* ========================================================================
  1360.  * Signal and error handler.
  1361.  */
  1362. RETSIGTYPE abort_gzip()
  1363. {
  1364.    if (remove_ofname) {
  1365.        close(ofd);
  1366.        unlink (ofname);
  1367.    }
  1368.    do_exit(ERROR);
  1369. }
  1370.